'''
使用方法:
调用 run_app() 函数
'''

import aiohttp
import asyncio
import re
import os
import common
from hexbytes import HexBytes

from aiohttp import web
from collections import namedtuple
import functools
import json
from appenv import AppEnv
from aiohttptools import OK,FAILED
from db import DBHelper
from myeth import MyTransaction
import routes
from common.strtools import hex_add_0x,hex_remove_0x
from encrypter import MyAES

class WebApp:
    def __init__(self,app_env:AppEnv):
        self.env = app_env
        self.ip = common.args.ClientWebIP
        self.port = common.args.ClientWebPort
        # self.edgeRequestHandler = edgeRequestHandler
        # self.clientRequestHandler = clientRequestHandler
        self.RouteParam = namedtuple(
            "RouteParam", ["method", "path", "handler"])
        self.route_param_list = []

    def run_app_in_loop(self,loop):
        asyncio.set_event_loop(loop)
        loop.run_until_complete(self.init_app(loop))

    def run_app(self):
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        loop.run_until_complete(self.init_app(loop))
        loop.run_forever()
        pass

    async def init_app(self, loop):
        app = web.Application(loop=loop)
        self._build_controllers()
        # self._init_add_static(app)
        self._init_add_route(app)
        srv = await loop.create_server(app.make_handler(), self.ip, self.port)
        print('Py server started at {}:{}...'.format(self.ip, self.port))
        return srv

    '''
    以下为初始化函数
    '''

    def _init_add_route(self, app):
        '''
        为webapp设置路由
        '''
        for ele in self.route_param_list:
            app.router.add_route(ele.method, ele.path, ele.handler)

    
    # def controller(self, method, path):
    #     '''
    #     controller装饰器，模仿springboot
    #     '''
    #     def wrapper(func):
    #         self.route_param_list.append(self.RouteParam(
    #             method=method, path=path, handler=func))
    #         return func            
    #     return wrapper

    def controller(self, method, path):
        '''
        controller装饰器，模仿springboot
        '''
        def wrapper(func):
            f = func
            self.route_param_list.append(self.RouteParam(
                method=method, path=path, handler=f))
            return f            
        return wrapper


    def log(self,request):
        common.print_msg("webapp",request)

    
    def _build_controllers(self):
        '''
        controllers
        '''

        @self.controller("GET",routes.acct_address)
        async def get_acct_address(request:web.Request):
            self.log(request)
            address = self.env.get_acct_address()
            return web.Response(body=address)

        @self.controller("POST",routes.file_sharing_registration)
        async def register(request:web.Request):
            self.log(request)
            #+++++++++++++++++++++++
            # TODO 
            #   其实没用了，没有做到 NAT 穿透，只能装装样子
            #+++++++++++++++++++++++
            ip = request.remote
            url = f"http://{ip}:{common.args.ClientWebPort}{routes.receive}" 
            await self.env.save_request_json_in_third_step(request,url)
            # return web.Response(body="OK")
            return OK()

        @self.controller("POST",routes.receive)
        async def receive(request:web.Request):
            self.log(request)
            ans_of_the_fifth_step = await self.env.DU_receive_response_in_the_fifth_step(
                request
            )
            ret_json = ans_of_the_fifth_step
            """
            ret_json["content"]:
            ABE_key_txn_id = json_content["transaction_id"]
            contrat_address = json_content["contract_address"]
            contract_abi = json_content["contract_abi"]
            contract_src = json_content["contract_src"]
            """
            DBHelper.save_contract(
                owner_acct_address = ret_json["address"],
                contract_address = ret_json["content"]["contract_address"],
                contract_abi = json.dumps(ret_json["content"]["contract_abi"]), # ???
                contract_src = ret_json["content"]["contract_src"],
                is_DO_contract = True
            )
            # TODO ABE_key_txn_id = json_content["transaction_id"] 这个还没处理
            ABE_key_txn_id = ret_json["content"]["transaction_id"]
            my_txn = MyTransaction(txn_hash=ABE_key_txn_id)
            encrypted_data = my_txn.get_data()
            # 获取 shared_key 
            _SharedKeyRecord = DBHelper.get_SharedKey(
                this_side_acct_addr = hex_add_0x(self.env.acct_address),
                the_other_side_acct_addr = hex_add_0x(ret_json["address"])
            )
            shared_key = _SharedKeyRecord.the_key
            _AES = MyAES(shared_key)
            # 解密出 ABE 信息
            _ABE_json_str = _AES.decrypt(encrypted_data)
            _ABE_json = json.loads(_ABE_json_str)
            _ABE_priv_key = _ABE_json["private_key"]
            _ABE_pub_key = _ABE_json["public_key"]
            # 存 ABE 信息
            DBHelper.save_ABEUserKey(
                user_acct_addr = self.env.acct_address,
                master_acct_addr = ret_json["address"],
                private_key = _ABE_priv_key,
                public_key = _ABE_pub_key
            )
            # # 暂时告一段落
            return OK()

    
        

        
